/**
 * Copyright 2010 - YangJiandong(chunquedong)
 * 
 * This file is part of ChunMap project
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
 * 
 * ChunMap是开源软件。你可以自由复制、传播本项目的下载包文件，但必须保持其完整性。
 * 我们不用对使用中的风险及由此造成的损失承担任何责任。
 * 详细情况请见《ChunMap许可协议》。
 * 
 * 想了解更多有关ChunMap的信息，请访问http://code.google.com/p/chunmap/
 * 
 * 下面此段程序作者YangJianDong(chunquedong)
 * 最后修改时间2010.7.17
 */
package chunmap.raster.gmap;

import java.util.ArrayList;
import java.util.List;

import chunmap.model.coord.Position;
import chunmap.model.crs.proj.Mercator;
import chunmap.model.elem.Envelope;
import chunmap.raster.Tile;

public class GoogleMapCode {
	public static final int tileSize = 256;//每个瓦片的像素大小
    public static final double dis = Mercator.maxDis * 2;//墨卡托投影展开的宽度
    public static final double originScale = tileSize / dis;//一个瓦片显示全球时的比例尺


    private int countX;
    private double sizeX;

    private void init(int zoom)
    {
        countX = (int)Math.pow(2, zoom);//水平或者垂直Tile个数
        sizeX = dis / countX;//每个Tile的大小，投影坐标下

    }

    public List<GMTile> getTileSet(Envelope envelope, double scale)
    {
        List<GMTile> tileSet = new ArrayList<GMTile>();

        int zoom = scale2zoom(scale);
        if (zoom < 0)
        {
            GMTile t = new GMTile(0, 0, 0);
            tileSet.add(t);
            return tileSet;
        }

        //初始化参数
        init(zoom);

        GMTile minT = getTile(zoom, envelope.leftUp(), countX, sizeX,true);
        GMTile maxT = getTile(zoom, envelope.rightDown(), countX, sizeX,false);

        for (int i = minT.x; i <= maxT.x; i++)
        {
            for (int j = minT.y; j <= maxT.y; j++)
            {
                GMTile tile = new GMTile(i, j, zoom);
                normallize(tile, countX);
                tileSet.add(tile);
            }
        }

        return tileSet;
    }
    //由比例尺计算zoom
    private int scale2zoom(double scale)
    {
        double curScale = originScale;
        
        int i = -1;
        while (curScale < scale*1.5)
        {
            curScale = curScale * 2d;
            i++;
        }

        return i;
    }
    //由点坐标得到瓦片坐标
    private GMTile getTile(int zoom, Position p, int countX, double sizeX
        , boolean isLeftUp)
    {
        double indexX = (p.getX() + Mercator.maxDis) / sizeX;
        double indexY = (Mercator.maxDis - p.getY()) / sizeX;
        if (isLeftUp)
        {
            indexX = indexX - 1;
            indexY = indexY - 1;
        }

        int ix = (int)indexX;
        int iy = (int)indexY;

        return new GMTile(ix, iy, zoom);
    }

    //正规化瓦片
    private void normallize(GMTile tile, int count)
    {
        int n = subNormalize(tile.x, count);
        if (n != -1)
        {
            tile.createProxy();
            tile.proxy.x = n;
        }

        int n2 = subNormalize(tile.y, count);
        if (n2 != -1)
        {
            tile.createProxy();
            tile.proxy.y = n2;
        }
    }
    private int subNormalize(int x, int c)
    {
        if (x >= c)
        {
            return x % c;
        }
        else if (x < 0)
        {
            int t = x % c;
            if (t >= 0) return t;
            return t + c;
        }
        else
        {
            return -1;
        }
    }

    /// <summary>
    /// 得到tile所占的Envelope
    /// </summary>
    /// <param name="tile"></param>
    /// <returns></returns>
    public Envelope getEnvelope(Tile tile)
    {
        int countX = (int)Math.pow(2, (tile.z));//水平或者垂直Tile个数
        double sizeX = dis / countX;//每个Tile的大小，投影坐标下

        double minX = (tile.x * sizeX) - Mercator.maxDis;
        double maxY = Mercator.maxDis - (tile.y * sizeX);

        return new Envelope(minX, maxY-sizeX, minX + sizeX, maxY);
    }
}
